//
//  Objc.swift
//  Extend
//
//  Created by 元穗 on 2017/5/27.
//  Copyright © 2017年 敬信. All rights reserved.
//

/// 在拓展里面定义属性, 以下是例子
/**
 extension UITapGestureRecognizer {
    struct Keys {
        static fileprivate var indexPath: IndexPath = IndexPath();
    }
 
    public var indexPath: IndexPath {
        get {
            return associated(to: self, key: &Keys.indexPath) { IndexPath() };
        }
        set {
            associate(to: self, key: &Keys.indexPath, value: newValue);
        }
    }
 }
 */

import ObjectiveC

final class Lifted<T> {
    let value: T
    init(_ x: T) {
        value = x
    }
}

private func lift<T>(_ x: T) -> Lifted<T> {
    return Lifted(x)
}

func associated<T>(to base: AnyObject,
                   key: UnsafeRawPointer,
                   policy: objc_AssociationPolicy = .OBJC_ASSOCIATION_RETAIN,
                   initializer: () -> T) -> T {
    if let v = objc_getAssociatedObject(base, key) as? T {
        return v
    }

    if let v = objc_getAssociatedObject(base, key) as? Lifted<T> {
        return v.value
    }

    let lifted = Lifted(initializer())
    objc_setAssociatedObject(base, key, lifted, policy)
    return lifted.value
}

func associate<T>(to base: AnyObject, key: UnsafeRawPointer, value: T, policy: objc_AssociationPolicy = .OBJC_ASSOCIATION_RETAIN) {
    if let v: AnyObject = value as AnyObject? {
        objc_setAssociatedObject(base, key, v, policy)
    } else {
        objc_setAssociatedObject(base, key, lift(value), policy)
    }
}
